//
//  ThreadPool.swift
//  JKTools
//
//  Created by 姜奎 on 2024/9/11.
//

import Foundation

// 定义任务类型，包含优先级和执行体
public
class ThreadPool {
    public typealias Task = (Int, OperationQueue)
    private var tasks: [Task] = [] // 任务队列
    private let maxConcurrency: Int // 最大并发数
    private let queue = DispatchQueue(label: "com.jk.queue.concurrent", attributes: .concurrent) // 系统提供的并发队列
    private var isRunning = false // 线程池是否正在运行
    private var completionHandlers: [(Bool) -> Void] = [] // 任务完成回调集合

    init(maxConcurrency: Int = ProcessInfo.physicalcpu) {
        self.maxConcurrency = maxConcurrency
    }

    // 添加任务到队列
    func addTask(priority: Int, handle: @escaping () -> Void) {
        if let task = tasks.first(where: { priority == $0.0 }) {
            task.1.addOperation(handle)
        } else {
            let operationQueue = OperationQueue(maxConcurrentOperationCount: maxConcurrency, underlyingQueue: self.queue, name: "\(self.queue.label)-\(priority)", startSuspended: true)
            operationQueue.addOperation(handle)
            tasks.append((priority, operationQueue))
            tasks.sort(by: { $0.0 > $1.0 })
        }
    }

    // 开始执行任务
    final func start() {
        guard !isRunning else { return }
        isRunning = true
        executeNextTask()
    }

    // 执行下一个任务
    private func executeNextTask() {
        guard !allTasksCompleted() else {
            isRunning = false
            completionHandlers.forEach { $0(true) }
            completionHandlers.removeAll()
            return
        }

        let task = tasks.removeFirst()
        task.1.isSuspended = false
        task.1.waitUntilAllOperationsAreFinished()
        executeNextTask()
    }

    // 检查所有任务是否已完成
    private func allTasksCompleted() -> Bool {
        return tasks.isEmpty
    }

    // 注册任务全部完成的回调
    func whenAllTasksCompleted(_ completionHandler: @escaping (Bool) -> Void) {
        completionHandlers.append(completionHandler)
    }
}

fileprivate
extension OperationQueue {
    convenience init(qualityOfService: QualityOfService = .default,
                     maxConcurrentOperationCount: Int = OperationQueue.defaultMaxConcurrentOperationCount,
                     underlyingQueue: DispatchQueue? = nil,
                     name: String? = nil,
                     startSuspended: Bool = false) {
        self.init()
        self.qualityOfService = qualityOfService
        self.maxConcurrentOperationCount = maxConcurrentOperationCount
        self.underlyingQueue = underlyingQueue
        self.name = name
        isSuspended = startSuspended
    }
}
